"""
性能监控仪表板演示脚本 - 展示完整功能
"""
import asyncio
import random
import time
import json
from datetime import datetime, timedelta
import aiohttp
import logging
from typing import Dict, Any

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# 模拟数据生成器
class MockDataGenerator:
    """模拟数据生成器"""
    
    def __init__(self):
        self.start_time = datetime.utcnow()
        self.total_requests = 0
        self.successful_requests = 0
        self.failed_requests = 0
        self.timeout_requests = 0
        
        # 基础性能指标
        self.base_mean_response_time = 150.0
        self.base_p90_response_time = 250.0
        self.base_p95_response_time = 350.0
        self.base_p99_response_time = 500.0
        
        # 吞吐量基准
        self.base_rps = 100.0
        self.base_rpm = 6000.0
        
        # 错误率基准
        self.base_error_rate = 0.5
        self.base_timeout_rate = 0.1
        
        # 资源使用基准
        self.base_cpu_usage = 45.0
        self.base_memory_usage = 60.0
        
        # 智能体类型
        self.agent_types = ['text_qa', 'doc_qa', 'multi_modal', 'tool_call', 'orchestrator']
    
    def generate_response_time_metrics(self) -> Dict[str, float]:
        """生成响应时间指标"""
        # 添加随机波动
        variation = random.uniform(-0.2, 0.3)
        
        mean_rt = max(50, self.base_mean_response_time * (1 + variation))
        p90_rt = mean_rt * random.uniform(1.5, 1.8)
        p95_rt = p90_rt * random.uniform(1.2, 1.4)
        p99_rt = p95_rt * random.uniform(1.3, 1.6)
        
        return {
            'mean': round(mean_rt, 1),
            'p90': round(p90_rt, 1),
            'p95': round(p95_rt, 1),
            'p99': round(p99_rt, 1)
        }
    
    def generate_throughput_metrics(self) -> Dict[str, float]:
        """生成吞吐量指标"""
        variation = random.uniform(-0.1, 0.2)
        
        rps = max(50, self.base_rps * (1 + variation))
        rpm = rps * 60
        
        return {
            'rps': round(rps, 1),
            'rpm': round(rpm, 1)
        }
    
    def generate_error_metrics(self) -> Dict[str, float]:
        """生成错误率指标"""
        # 偶尔产生错误高峰
        if random.random() < 0.1:  # 10%概率产生错误高峰
            error_rate = random.uniform(2.0, 8.0)
            timeout_rate = random.uniform(0.5, 2.0)
        else:
            error_variation = random.uniform(-0.3, 0.5)
            timeout_variation = random.uniform(-0.5, 0.8)
            
            error_rate = max(0.1, self.base_error_rate * (1 + error_variation))
            timeout_rate = max(0.01, self.base_timeout_rate * (1 + timeout_variation))
        
        return {
            'error_rate': round(error_rate, 2),
            'timeout_rate': round(timeout_rate, 2)
        }
    
    def generate_resource_metrics(self) -> Dict[str, float]:
        """生成资源使用指标"""
        # 模拟资源使用波动
        cpu_variation = random.uniform(-0.2, 0.4)
        memory_variation = random.uniform(-0.15, 0.3)
        
        cpu_usage = max(10, min(95, self.base_cpu_usage * (1 + cpu_variation)))
        memory_usage = max(20, min(90, self.base_memory_usage * (1 + memory_variation)))
        
        # 磁盘和网络IO
        disk_io = random.uniform(10, 100)
        network_io = random.uniform(50, 200)
        
        return {
            'cpu_usage': round(cpu_usage, 1),
            'memory_usage': round(memory_usage, 1),
            'disk_io': round(disk_io, 1),
            'network_io': round(network_io, 1)
        }
    
    def generate_agent_metrics(self) -> Dict[str, Dict[str, Any]]:
        """生成智能体特定指标"""
        agent_metrics = {}
        
        for agent_type in self.agent_types:
            # 不同智能体类型的基准值
            if agent_type == 'orchestrator':
                base_task_count = random.randint(5, 15)
                base_success_rate = random.uniform(95, 99)
                base_response_time = random.uniform(80, 150)
            elif agent_type == 'text_qa':
                base_task_count = random.randint(20, 50)
                base_success_rate = random.uniform(92, 98)
                base_response_time = random.uniform(100, 200)
            elif agent_type == 'doc_qa':
                base_task_count = random.randint(15, 35)
                base_success_rate = random.uniform(90, 96)
                base_response_time = random.uniform(200, 400)
            elif agent_type == 'multi_modal':
                base_task_count = random.randint(10, 25)
                base_success_rate = random.uniform(88, 95)
                base_response_time = random.uniform(300, 600)
            else:  # tool_call
                base_task_count = random.randint(12, 30)
                base_success_rate = random.uniform(93, 97)
                base_response_time = random.uniform(150, 300)
            
            agent_metrics[agent_type] = {
                'task_count': base_task_count,
                'success_rate': round(base_success_rate, 1),
                'avg_response_time': round(base_response_time, 1)
            }
        
        return agent_metrics
    
    def generate_summary_stats(self) -> Dict[str, int]:
        """生成汇总统计"""
        # 模拟请求增长
        requests_increment = random.randint(50, 150)
        self.total_requests += requests_increment
        
        # 根据错误率计算成功和失败请求
        error_rate = self.base_error_rate / 100
        timeout_rate = self.base_timeout_rate / 100
        
        successful_increment = int(requests_increment * (1 - error_rate))
        failed_increment = int(requests_increment * error_rate)
        timeout_increment = int(failed_increment * timeout_rate)
        
        self.successful_requests += successful_increment
        self.failed_requests += failed_increment
        self.timeout_requests += timeout_increment
        
        return {
            'total_requests': self.total_requests,
            'successful_requests': self.successful_requests,
            'failed_requests': self.failed_requests,
            'timeout_requests': self.timeout_requests
        }
    
    def generate_full_metrics(self) -> Dict[str, Any]:
        """生成完整的性能指标"""
        return {
            'response_time': self.generate_response_time_metrics(),
            'throughput': self.generate_throughput_metrics(),
            'error_rate': self.generate_error_metrics(),
            'resource_usage': self.generate_resource_metrics(),
            'agent_metrics': self.generate_agent_metrics(),
            'summary': self.generate_summary_stats(),
            'timestamp': datetime.utcnow().isoformat()
        }


# 仪表板客户端
class DashboardClient:
    """仪表板客户端"""
    
    def __init__(self, base_url: str = "http://localhost:8080"):
        self.base_url = base_url
        self.session = None
    
    async def __aenter__(self):
        self.session = aiohttp.ClientSession()
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        if self.session:
            await self.session.close()
    
    async def push_metrics(self, metrics: Dict[str, Any]) -> bool:
        """推送指标到仪表板"""
        try:
            async with self.session.post(
                f"{self.base_url}/api/metrics/push",
                json=metrics,
                timeout=aiohttp.ClientTimeout(total=5)
            ) as response:
                if response.status == 200:
                    result = await response.json()
                    return result.get('status') == 'success'
                else:
                    logger.warning(f"推送指标失败，状态码: {response.status}")
                    return False
        except Exception as e:
            logger.error(f"推送指标异常: {str(e)}")
            return False
    
    async def get_current_metrics(self) -> Dict[str, Any]:
        """获取当前指标"""
        try:
            async with self.session.get(
                f"{self.base_url}/api/metrics/current",
                timeout=aiohttp.ClientTimeout(total=5)
            ) as response:
                if response.status == 200:
                    return await response.json()
                else:
                    logger.warning(f"获取当前指标失败，状态码: {response.status}")
                    return {}
        except Exception as e:
            logger.error(f"获取当前指标异常: {str(e)}")
            return {}
    
    async def get_historical_metrics(self, time_range: str = '1h') -> Dict[str, Any]:
        """获取历史指标"""
        try:
            async with self.session.get(
                f"{self.base_url}/api/metrics/historical?range={time_range}",
                timeout=aiohttp.ClientTimeout(total=10)
            ) as response:
                if response.status == 200:
                    return await response.json()
                else:
                    logger.warning(f"获取历史指标失败，状态码: {response.status}")
                    return {}
        except Exception as e:
            logger.error(f"获取历史指标异常: {str(e)}")
            return {}


# 演示运行器
class DashboardDemoRunner:
    """仪表板演示运行器"""
    
    def __init__(self, dashboard_url: str = "http://localhost:8080", 
                 update_interval: int = 5):
        self.dashboard_url = dashboard_url
        self.update_interval = update_interval
        self.data_generator = MockDataGenerator()
        self.running = False
    
    async def run_demo(self, duration_minutes: int = 30):
        """运行演示"""
        logger.info(f"开始性能监控仪表板演示，持续时间: {duration_minutes}分钟")
        logger.info(f"仪表板地址: {self.dashboard_url}")
        logger.info(f"数据更新间隔: {self.update_interval}秒")
        
        self.running = True
        start_time = time.time()
        duration_seconds = duration_minutes * 60
        
        try:
            async with DashboardClient(self.dashboard_url) as client:
                # 检查仪表板是否可用
                if not await self._check_dashboard_available(client):
                    logger.error("仪表板不可用，请确保仪表板服务已启动")
                    return
                
                logger.info("仪表板连接成功，开始推送模拟数据...")
                
                iteration = 0
                while self.running and (time.time() - start_time) < duration_seconds:
                    try:
                        # 生成模拟数据
                        metrics = self.data_generator.generate_full_metrics()
                        
                        # 推送数据到仪表板
                        success = await client.push_metrics(metrics)
                        
                        if success:
                            iteration += 1
                            if iteration % 10 == 0:  # 每10次迭代显示一次统计
                                await self._display_statistics(client, iteration)
                        else:
                            logger.warning(f"第{iteration + 1}次数据推送失败")
                        
                        # 等待下一次更新
                        await asyncio.sleep(self.update_interval)
                        
                    except KeyboardInterrupt:
                        logger.info("收到中断信号，停止演示...")
                        self.running = False
                        break
                    except Exception as e:
                        logger.error(f"演示运行异常: {str(e)}")
                        await asyncio.sleep(self.update_interval)
                
                # 显示最终统计
                if iteration > 0:
                    await self._display_final_statistics(client, iteration)
                
                logger.info("性能监控仪表板演示结束")
                
        except Exception as e:
            logger.error(f"演示运行失败: {str(e)}")
    
    async def _check_dashboard_available(self, client: DashboardClient) -> bool:
        """检查仪表板是否可用"""
        try:
            metrics = await client.get_current_metrics()
            return len(metrics) > 0
        except Exception as e:
            logger.error(f"仪表板连接检查失败: {str(e)}")
            return False
    
    async def _display_statistics(self, client: DashboardClient, iteration: int):
        """显示统计信息"""
        try:
            current_metrics = await client.get_current_metrics()
            
            if current_metrics:
                logger.info(f"=== 第{iteration}次更新统计 ===")
                
                # 响应时间统计
                rt = current_metrics.get('response_time', {})
                logger.info(f"响应时间 - 平均: {rt.get('current_mean', 'N/A')}ms, "
                          f"P99: {rt.get('current_p99', 'N/A')}ms")
                
                # 吞吐量统计
                tp = current_metrics.get('throughput', {})
                logger.info(f"吞吐量 - RPS: {tp.get('current_rps', 'N/A')}, "
                          f"RPM: {tp.get('current_rpm', 'N/A')}")
                
                # 错误率统计
                er = current_metrics.get('error_rate', {})
                logger.info(f"错误率 - 总错误: {er.get('current_error_rate', 'N/A')}%, "
                          f"超时: {er.get('current_timeout_rate', 'N/A')}%")
                
                # 资源使用统计
                ru = current_metrics.get('resource_usage', {})
                logger.info(f"资源使用 - CPU: {ru.get('current_cpu', 'N/A')}%, "
                          f"内存: {ru.get('current_memory', 'N/A')}%")
                
                # 汇总统计
                summary = current_metrics.get('summary', {})
                logger.info(f"汇总 - 总请求: {summary.get('total_requests', 'N/A')}, "
                          f"成功: {summary.get('successful_requests', 'N/A')}, "
                          f"失败: {summary.get('failed_requests', 'N/A')}")
                
                logger.info("=" * 40)
                
        except Exception as e:
            logger.error(f"显示统计信息失败: {str(e)}")
    
    async def _display_final_statistics(self, client: DashboardClient, total_iterations: int):
        """显示最终统计"""
        try:
            current_metrics = await client.get_current_metrics()
            historical_metrics = await client.get_historical_metrics('1h')
            
            logger.info("=== 最终统计汇总 ===")
            logger.info(f"总数据推送次数: {total_iterations}")
            
            if current_metrics:
                summary = current_metrics.get('summary', {})
                logger.info(f"总请求数: {summary.get('total_requests', 'N/A')}")
                logger.info(f"成功请求: {summary.get('successful_requests', 'N/A')}")
                logger.info(f"失败请求: {summary.get('failed_requests', 'N/A')}")
                logger.info(f"超时请求: {summary.get('timeout_requests', 'N/A')}")
                
                if summary.get('total_requests', 0) > 0:
                    success_rate = (summary.get('successful_requests', 0) / summary.get('total_requests', 1)) * 100
                    logger.info(f"整体成功率: {success_rate:.2f}%")
            
            logger.info("=" * 40)
            
        except Exception as e:
            logger.error(f"显示最终统计失败: {str(e)}")
    
    def stop(self):
        """停止演示"""
        self.running = False


# 主要演示函数
async def run_dashboard_demo():
    """运行仪表板演示"""
    
    print("🚀 MAESS 性能监控仪表板演示")
    print("=" * 50)
    print("本演示将：")
    print("1. 连接到性能监控仪表板")
    print("2. 生成模拟的性能数据")
    print("3. 实时推送数据到仪表板")
    print("4. 展示仪表板的各项功能")
    print("=" * 50)
    
    # 演示配置
    dashboard_url = "http://localhost:8080"
    update_interval = 5  # 秒
    duration_minutes = 30  # 分钟
    
    # 创建演示运行器
    demo_runner = DashboardDemoRunner(
        dashboard_url=dashboard_url,
        update_interval=update_interval
    )
    
    try:
        # 运行演示
        await demo_runner.run_demo(duration_minutes=duration_minutes)
        
    except KeyboardInterrupt:
        logger.info("演示被用户中断")
        demo_runner.stop()
    
    except Exception as e:
        logger.error(f"演示运行失败: {str(e)}")
    
    finally:
        print("\n演示结束！")
        print(f"请访问 {dashboard_url} 查看仪表板")
        print(f"API文档: {dashboard_url}/api/docs")


# 快速测试函数
async def quick_dashboard_test():
    """快速测试仪表板"""
    
    print("🔧 快速测试仪表板功能...")
    
    # 创建数据生成器
    generator = MockDataGenerator()
    
    # 创建仪表板客户端
    async with DashboardClient("http://localhost:8080") as client:
        try:
            # 生成并推送一组测试数据
            metrics = generator.generate_full_metrics()
            
            print("生成的测试数据:")
            print(json.dumps(metrics, indent=2, ensure_ascii=False))
            
            # 推送到仪表板
            success = await client.push_metrics(metrics)
            
            if success:
                print("✅ 数据推送成功！")
                
                # 获取当前指标
                current_metrics = await client.get_current_metrics()
                print("\n当前仪表板指标:")
                print(json.dumps(current_metrics, indent=2, ensure_ascii=False))
                
            else:
                print("❌ 数据推送失败")
                
        except Exception as e:
            print(f"❌ 测试失败: {str(e)}")


# 性能压力测试
async def stress_test_dashboard():
    """对仪表板进行压力测试"""
    
    print("⚡ 开始仪表板压力测试...")
    
    generator = MockDataGenerator()
    
    async def send_metrics_batch(batch_size: int, batch_id: int):
        """发送一批指标数据"""
        async with DashboardClient("http://localhost:8080") as client:
            success_count = 0
            
            for i in range(batch_size):
                try:
                    metrics = generator.generate_full_metrics()
                    success = await client.push_metrics(metrics)
                    if success:
                        success_count += 1
                    
                    # 小延迟避免过载
                    await asyncio.sleep(0.01)
                    
                except Exception as e:
                    logger.error(f"批次{batch_id} 请求{i}失败: {str(e)}")
            
            return success_count
    
    # 测试参数
    total_batches = 10
    batch_size = 100
    concurrent_batches = 3
    
    print(f"测试参数: {total_batches}批次, 每批{batch_size}请求, {concurrent_batches}并发")
    
    start_time = time.time()
    total_success = 0
    total_requests = total_batches * batch_size
    
    # 执行并发测试
    for batch_group in range(0, total_batches, concurrent_batches):
        current_batch_count = min(concurrent_batches, total_batches - batch_group)
        
        tasks = [
            send_metrics_batch(batch_size, batch_group + i)
            for i in range(current_batch_count)
        ]
        
        results = await asyncio.gather(*tasks, return_exceptions=True)
        
        for result in results:
            if isinstance(result, int):
                total_success += result
            else:
                logger.error(f"批次异常: {result}")
        
        print(f"完成批次组 {batch_group + 1}-{batch_group + current_batch_count}")
    
    end_time = time.time()
    duration = end_time - start_time
    
    # 显示测试结果
    print("\n=== 压力测试结果 ===")
    print(f"总请求数: {total_requests}")
    print(f"成功请求: {total_success}")
    print(f"失败请求: {total_requests - total_success}")
    print(f"成功率: {(total_success / total_requests) * 100:.2f}%")
    print(f"总耗时: {duration:.2f}秒")
    print(f"平均RPS: {total_requests / duration:.2f}")


# 主函数
async def main():
    """主函数"""
    
    print("MAESS 性能监控仪表板演示程序")
    print("请选择要运行的模式:")
    print("1. 完整演示 (30分钟)")
    print("2. 快速测试")
    print("3. 压力测试")
    print("4. 退出")
    
    try:
        choice = input("\n请输入选择 (1-4): ").strip()
        
        if choice == '1':
            await run_dashboard_demo()
            
        elif choice == '2':
            await quick_dashboard_test()
            
        elif choice == '3':
            await stress_test_dashboard()
            
        elif choice == '4':
            print("退出程序")
            
        else:
            print("无效选择，退出程序")
            
    except KeyboardInterrupt:
        print("\n程序被用户中断")
    
    except Exception as e:
        print(f"程序运行出错: {str(e)}")


if __name__ == "__main__":
    # 运行主函数
    asyncio.run(main())